package org.yatr.yatrc;
import java.util.HashMap;
import java.util.LinkedHashMap;
import org.antlr.runtime.Token;
//import org.yatr.yatrc.TType;
import static org.yatr.yatrc.TType.*;
import static org.yatr.yatrc.Log.*;

class Symtbl {
	HashMap<String, TType> symtbl;

	static HashMap<String, TType> predefinedTypes;
	static void initPredefinedTypes() {
		predefinedTypes = new LinkedHashMap<String, TType>();
		predefinedTypes.put("integer", new TType("IntegerValueYatr", TAttrib.TYPE, TSubAttribTYPE.INTEGER));
		predefinedTypes.put("boolean", new TType("BooleanValueYatr", TAttrib.TYPE, TSubAttribTYPE.BOOLEAN));
		predefinedTypes.put("charstring", new TType("CharstringValueYatr", TAttrib.TYPE, TSubAttribTYPE.CHARSTRING));
	}

	static {
		initPredefinedTypes();
	}
	
	/**
	 * Default constructor, create a new HashMap itself.
	 */
	public Symtbl() {
		symtbl = new LinkedHashMap<String, TType>();
	}
	
	/*
	public Symtbl(HashMap<String, TType> sym) {
	    if(sym==null) {
	        return new RuntimeException("sym is null fail.");
	    }
	    symtbl = sym;
	}*/
	
	static TType getPredefinedType(String name) {
		return predefinedTypes.get(name);
	}
	
	static TType newModule(Token token) {
		//err check
		
		TType type = new TType(token, TAttrib.MODULE, null);
		return type;
	}
	
	static TType newFunction(Token token){
		//err check
		
		TType type = new FunctionType(token, TAttrib.FUNCTION, null);
		return type;
	}
	
	static TType newTestcase(Token token) {
		//err check
		
		TType type = new TestcaseType(token, TAttrib.TESTCASE, null);
		return type;
	}

	static TType newValue(Token token, TSubAttribVALUE s, TType typeOfValue) {
		//duplicate error check
		
		TType t = new TType(token, TAttrib.VALUE, s);
		t.setType(typeOfValue);
		return t;
	}
	
	static TType newType(Token t, TSubAttribTYPE s) {

		TType type =  new TType(t, TAttrib.TYPE, s);
		
		return type;
	}
	
	void addType(Token t, TType type) {
		if(null == type) {
			logError(t, "Unexpected type==null fail.");
			return;
		}
		//duplicate check here
		TType tt = symtbl.get(t.getText());
		if(null != tt) {
			logWarning(t, "Type name defined already previous.");
			if(tt.getAttrib() != type.getAttrib()) {
				logError(t, "previous define="+tt.getAttrib()+",current define="+type.getAttrib()+" error.");
			} else {
				symtbl.put(t.getText(), type);
			}
		} else {
			logInfo(t, "Add new %s.", t.getText());
			symtbl.put(t.getText(), type);
		}
	}
	
	void addTypeFast(String name, TType type) {
	    symtbl.put(name, type);
	}
	
	TType findType(Token t, TAttrib expect1, TSubAttrib expect2) {
		TType tmpt = symtbl.get(t.getText());
		if(null == tmpt) {
			logWarning(t, "Can not find %s.", t.getText());
		} else {
			if(null != expect1 && tmpt.getAttrib() != expect1) {
				logError(t, "Expect Attrib=" + expect1 + ", but "+tmpt.getAttrib()+" .");
				//return null;
			}
			if(expect2!=null && tmpt.getSubAttrib() != expect2) {
				logError(t, "Expect SubAttrib=" + expect2 + ", but "+tmpt.getSubAttrib()+" .");
			}
		}
		return tmpt;
	}
	
	TType findType(String tokenName, TAttrib expect1, TSubAttrib expect2) {
	    TType tmpt = symtbl.get(tokenName);
		if(null == tmpt) {
			logWarning(null, "Can not find %s.", tokenName);
		} else {
			if(null != expect1 && tmpt.getAttrib() != expect1) {
				logError(null, "Expect Attrib=" + expect1 + ", but "+tmpt.getAttrib()+" .");
				//return null;
			}
			if(expect2!=null && tmpt.getSubAttrib() != expect2) {
				logError(null, "Expect SubAttrib=" + expect2 + ", but "+tmpt.getSubAttrib()+" .");
			}
		}
        return tmpt;
	}
	
	public String toString() {
		return symtbl.toString();
	}

}
